package com.keepercloud.qqchat.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.keepercloud.qqchat.entity.ChatMessage;
import com.keepercloud.qqchat.entity.User;
import com.keepercloud.qqchat.framework.common.config.GetHttpSessionConfigurator;
import com.keepercloud.qqchat.framework.common.exception.BackLoginException;
import com.keepercloud.qqchat.framework.common.exception.SimpleException;
import com.keepercloud.qqchat.framework.common.utils.SpringContextUtils;
import com.keepercloud.qqchat.service.ChatMessageService;
import com.keepercloud.qqchat.util.UserUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 *
 * @author liyk
 */
@ServerEndpoint(value = "/websocket", configurator = GetHttpSessionConfigurator.class)
@Component
public class WebSocketController {

//    private final ChatMessageService chatMessageService;

    /**
     * 静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
     */
    private static int onlineCount = 0;

    /**
     * concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
     */
    private static ConcurrentHashMap<String, WebSocketController> webSocketMap = new ConcurrentHashMap<>();


    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 当前登录用户名
     */
    private String username;


    private ChatMessageService chatMessageService;

//    @Autowired
//    public WebSocketController(ChatMessageService chatMessageService) {
//        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
//        this.chatMessageService = chatMessageService;
//    }


    /**
     * 连接建立成功调用的方法*/
    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
        this.chatMessageService = SpringContextUtils.getBean(ChatMessageService.class);
        // 此处由于ws / http 协议不同, 不可以通过上下文获取到用户名
        HttpSession httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
        User currUser = (User) httpSession.getAttribute("currUser");
        if (currUser == null) {
            throw new BackLoginException("请先登录");
        }
        String userName = currUser.getUsername();
        this.session = session;
        this.username = userName;
        webSocketMap.put(userName, this);
        addOnlineCount();           //在线数加1
        System.out.println("有新连接加入！当前在线人数为" + getOnlineCount());
//        try {
//            sendMessage("成功建立连接");
//        } catch (IOException e) {
//            System.out.println("IO异常");
//        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketMap.remove(this.username);
        subOnlineCount();           //在线数减1
        System.out.println("有一连接关闭！当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        JSONObject jsonObject = JSON.parseObject(message);
        if (jsonObject.size() != 2) {
            throw new SimpleException("发送的消息格式有问题");
        }
        String toUsername = jsonObject.getString("toUsername");
        String userMsg = jsonObject.getString("message");
        System.out.println("来自客户端的消息:" + userMsg);
        if ("all".equals(toUsername)) {
            // TODO 全体消息后续处理
            sendToAll(userMsg);
        } else {
            WebSocketController webSocketController = webSocketMap.get(toUsername);
            ChatMessage chatMessage = new ChatMessage();
            chatMessage.setFromUsername(this.username);
            chatMessage.setToUsername(toUsername);
            Date date = new Date();
            chatMessage.setHappenedDate(date);
            chatMessage.setHasRead(false);
            chatMessage.setMessage(userMsg);
            chatMessageService.save(chatMessage);
            if (webSocketController != null) {
                JSONObject json = new JSONObject();
                json.put("fromUsername", this.username);
                json.put("message", userMsg);
                json.put("date", date);
                webSocketController.sendMessage(JSON.toJSONString(json));
            }
        }
    }

    /**
     * 发生错误时调用
    */
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("发生错误");
        error.printStackTrace();
    }


    private void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
        //this.session.getAsyncRemote().sendText(message);
    }


    /**
     * 群发自定义消息
     * */
    private static void sendToAll(String message) {
        for (Map.Entry<String, WebSocketController> entry : webSocketMap.entrySet()) {
            String key = entry.getKey();
            WebSocketController value = entry.getValue();
            try {
                value.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    private static synchronized void addOnlineCount() {
        WebSocketController.onlineCount++;
    }

    private static synchronized void subOnlineCount() {
        WebSocketController.onlineCount--;
    }
}